package ai.phase.cognition.development.simplebeam;
import ai.algorithms.interruptible.*;
import ai.*;
import java.util.*;

public class BeamRegion implements ChoiceNode{

	
	private BeamAgent j_AgentParent;
	private SimpleGoalIndicator j_GoalIndicator;
	private HashMap<Integer, BeamRegion> j_AdjacentRegions;
	private int j_Score=0;
	
	
	// Region desirability parameters
	private int j_LastUtility=0;
	private int j_lastVisited=0;
	private double j_TIMEWEIGHT=1;
	private double j_UTILITYWEIGHT=1;
	
	// Info on what happened to the region
	
	private Integer j_ActionTaken;
	
	private LinkedList<Integer> j_ActionOptionList;
	private Integer[] j_ChoiceVector;
	private List<WeightedValue<Integer>> j_Weights;
	
	public BeamRegion(SimpleGoalIndicator gIndicator,BeamAgent parent )
	{
		j_GoalIndicator=gIndicator;
		j_AdjacentRegions=new HashMap<Integer,BeamRegion>();
		j_AgentParent=parent;
		j_lastVisited=1;
		j_LastUtility=0;
		
	}
	
	public void AssertVisited(int[] availableActions, int utility)
	{
		j_LastUtility=utility;
		j_lastVisited=0;
		j_ChoiceVector = new Integer[availableActions.length];
		Integer option;
		HashMap<Integer, BeamRegion> newAdjacent = new HashMap<Integer, BeamRegion>();
		
		for (int i=0;i<availableActions.length;i++)
		{
			option= new Integer(availableActions[i]);
			j_ChoiceVector[i]=option;
			if (!j_AdjacentRegions.containsKey(option))
				j_AdjacentRegions.put(option, j_AgentParent.MakeRegion());
			
			newAdjacent.put(option, j_AdjacentRegions.get(option));
		}
		j_AdjacentRegions=newAdjacent;
	}
	
	
	
	
	public BeamRegion AssertActionTaken(Integer action)
	{
		j_ActionTaken=action;
		if (action==null)
			return this;
		if (j_AdjacentRegions.containsKey(action))
			return j_AdjacentRegions.get(j_ActionTaken);
		else
			 return null;
	}
	
	
	public void AssertNextStep()
	{
		j_lastVisited++;
	}
	public void AssertNextRegion(int[] availableActions, int utility)
	{
		BeamRegion mappedRegion = j_AdjacentRegions.get(j_ActionTaken);
		mappedRegion.AssertVisited(availableActions, utility);
	}
	
	
	// If the region has been visited before
	public void AssertNextRegion(BeamRegion region)
	{
		BeamRegion mappedRegion = j_AdjacentRegions.get(j_ActionTaken);
		// maybe do something with the prior region
		j_AdjacentRegions.put(j_ActionTaken, region);
	}
	
	
	public double GetScore()
	{
		return j_TIMEWEIGHT*j_lastVisited+j_UTILITYWEIGHT*j_LastUtility;
	}
	
	
	@Override
	public boolean GoalReachedP() {
		// TODO Auto-generated method stub
		return j_GoalIndicator.IsGoal(this);
	}

	@Override
	public ChoicePointer NextChoice() {
		// TODO Auto-generated method stub

		WeightedValue<Integer> actionScoreWeightedPair=null,maxActionScoreWeightedPair=null;

		for (int i=0;i<j_Weights.size();i++ )
		{
			// Get the score of the region pointed to by action i
			actionScoreWeightedPair=j_Weights.get(i);
			if (maxActionScoreWeightedPair==null)
			{
				maxActionScoreWeightedPair=actionScoreWeightedPair;
			}
			else
			{
				if (actionScoreWeightedPair.GetWeight()>=maxActionScoreWeightedPair.GetWeight())
				{
					maxActionScoreWeightedPair=actionScoreWeightedPair;
				}
			}
			
		}
		if ((maxActionScoreWeightedPair==null)||(maxActionScoreWeightedPair.GetWeight()<=0.0))
			return null;
		
		maxActionScoreWeightedPair.ZeroWeight();
		
		return new RegionPointer(this,maxActionScoreWeightedPair.GetValue());
	}

	@Override
	public void ResetNode() {
		// TODO Auto-generated method stub
		j_ActionOptionList = new LinkedList<Integer>();
		j_Weights = new LinkedList<WeightedValue<Integer>>();
		Integer actionIndex;
		BeamRegion mappedRegion;
		WeightedValue<Integer> actionScorePair=null;
		double score;
		if (j_ChoiceVector==null)
			return;
		for (int i=0;i<j_ChoiceVector.length;i++)
		{
			actionIndex=j_ChoiceVector[i];
			mappedRegion=j_AdjacentRegions.get(actionIndex);
			score=mappedRegion.GetScore();
			actionScorePair = new WeightedValue<Integer>(actionIndex,score);
			j_Weights.add(actionScorePair);
			
		}
	}

	public static class RegionPointer implements ChoicePointer {

		private Integer j_ChoiceId;
		private BeamRegion j_Parent;
		public RegionPointer(BeamRegion parent, Integer pointerId)
		{
			
			j_ChoiceId=pointerId;
			j_Parent=parent;
		}
		
		@Override
		public ChoiceNode ResolveNode() {
			
			return j_Parent.j_AdjacentRegions.get(j_ChoiceId);
		}

		
		public Integer GetActionId()
		{
			return j_ChoiceId;
		}
	}
	
}
